package com.bifang.core.dict.util;

import com.bifang.common.exception.AppException;
import com.bifang.common.interfaces.DictType;
import com.bifang.common.vo.SelectVO;
import com.bifang.core.dict.integration.DictIntegration;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

/**
 * @author chenzh
 * @date 2019/5/8 22:06
 */
@Service
public class DictUtil {

    /** 转义的字典名称必须以xxxName定义，否则无法自动匹配 */
    public static final String SUFFIX = "Name";

    @Autowired private DictIntegration dictIntegration;

    /**
     * 单个字典校验
     *
     * @param data
     * @param dictType
     * @param <T>
     */
    public <T> void validValue(T data, DictType dictType) {
        validValue(data, Arrays.asList(dictType));
    }

    /**
     * 批量字段校验
     *
     * @param data
     * @param dictTypeList
     * @param <T>
     */
    public <T> void validValue(T data, List<DictType> dictTypeList) {
        if (data == null || CollectionUtils.isEmpty(dictTypeList)) {
            return;
        }
        // 查询字典值列表
        Map<String, Map<String, String>> dictDataVOList = getDictMapList(dictTypeList);
        if (CollectionUtils.isEmpty(dictDataVOList)) {
            return;
        }

        int size = dictDataVOList.size();
        // 挨个转义字典值
        for (int i = 0; i < size; i++) {
            DictType dictType = dictTypeList.get(i);
            String property = dictType.getPropertyName();
            String dictKey = getDictValue(data, property);
            if (StringUtils.isBlank(dictKey)) {
                continue;
            }
            Map<String, String> dictMap = dictDataVOList.get(dictType.getPropertyName());
            if (dictMap == null) {
                throw new AppException("无效的[" + dictTypeList.get(i).getFieldName() + "]字典数据");
            } else {
                if (StringUtils.isBlank(dictMap.get(dictKey))) {
                    throw new AppException("无效的[" + dictTypeList.get(i).getFieldName() + "]字典数据");
                }
            }
        }
    }

    /**
     * 单条数据单字典转义
     *
     * @param data
     * @param dictType 字典类型
     * @param <T>
     */
    public <T> void valueToName(T data, DictType dictType) {
        valueToName(Arrays.asList(data), Arrays.asList(dictType));
    }

    public <T> void valueToName(T data, DictType dictType, boolean flag) {
        valueToName(Arrays.asList(data), Arrays.asList(dictType), flag);
    }
    /**
     * 单条数据多字典转义
     *
     * @param data
     * @param dictTypeList
     * @param <T>
     */
    public <T> void valueToName(T data, List<DictType> dictTypeList) {
        valueToName(Arrays.asList(data), dictTypeList);
    }

    public <T> void valueToName(T data, List<DictType> dictTypeList, boolean flag) {
        valueToName(Arrays.asList(data), dictTypeList, flag);
    }

    /**
     * 多条数据单字典转义
     *
     * @param dataList
     * @param dictType
     * @param <T>
     */
    public <T> void valueToName(List<T> dataList, DictType dictType) {
        valueToName(dataList, Arrays.asList(dictType));
    }

    public <T> void valueToName(List<T> dataList, DictType dictType, boolean flag) {
        valueToName(dataList, Arrays.asList(dictType), flag);
    }
    /**
     * 多条数据多字典转义
     *
     * @param dataList 数据列表
     * @param dictTypeList 对应的字典属性列表
     * @param <T>
     */
    public <T> void valueToName(List<T> dataList, List<DictType> dictTypeList) {
        this.valueToName(dataList, dictTypeList, false);
    }

    public <T> void valueToName(List<T> dataList, List<DictType> dictTypeList, boolean flag) {
        if (CollectionUtils.isEmpty(dataList) || CollectionUtils.isEmpty(dictTypeList)) {
            return;
        }
        // 查询字典值列表
        Map<String, Map<String, String>> dictDataVOList = getDictMapList(dictTypeList);
        if (CollectionUtils.isEmpty(dictDataVOList)) {
            return;
        }

        for (T data : dataList) {
            setValue(data, dictTypeList, dictDataVOList, 1, flag);
        }
    }

    private <T> void setValue(
            T data,
            List<DictType> dictTypeList,
            Map<String, Map<String, String>> dictDataVOList,
            Integer count,
            boolean flag) {
        if (count > 10) {
            return;
        }
        Class cls = data.getClass();
        String typeName = cls.getTypeName();
        if (typeName.indexOf("java.lang") >= 0
                || typeName.indexOf("java.util") >= 0
                || typeName.indexOf("java.math") >= 0) {
            return;
        }
        // 最多10层转换
        count = count + 1;
        BeanWrapper beanWrapper = new BeanWrapperImpl(data);
        int size = dictTypeList.size();
        // 挨个转义字典值
        for (int i = 0; i < size; i++) {
            DictType dictType = dictTypeList.get(i);
            String property = dictType.getPropertyName();
            String nameProperty = property + SUFFIX;

            String dictKey = getDictValue(data, property);
            if (dictKey == null) {
                continue;
            }
            // SelectVO dictDataVO = filter(dictDataVOList.get(dictType.getPropertyName()),
            // dictKey);
            Map<String, String> dictMap = dictDataVOList.get(dictType.getPropertyName());
            if (dictMap != null
                    && beanWrapper.isWritableProperty(nameProperty)
                    && ObjectUtils.isEmpty(beanWrapper.getPropertyValue(nameProperty))) {
                beanWrapper.setPropertyValue(nameProperty, dictMap.get(dictKey));
            }
        }
        if (flag) {
            Field[] fields = cls.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field f = fields[i];
                boolean isStatic = Modifier.isStatic(f.getModifiers());
                if (isStatic) { // 静态变量不处理
                    continue;
                }
                f.setAccessible(true);
                String type = f.getType().getTypeName().toLowerCase();
                if (type.indexOf("java.lang") < 0
                        && type.indexOf("java.util") < 0
                        && type.indexOf("java.math") < 0) {
                    Object obj = beanWrapper.getPropertyValue(f.getName());
                    if (obj != null) {
                        setValue(obj, dictTypeList, dictDataVOList, count, flag);
                    }
                }
                if (type.indexOf("list") > 0) {
                    List<T> list = (List) beanWrapper.getPropertyValue(f.getName());
                    if (!CollectionUtils.isEmpty(list)) {
                        for (T obj : list) {
                            setValue(obj, dictTypeList, dictDataVOList, count, flag);
                        }
                    }
                }
            }
        }
    }
    /**
     * 获取字典类型
     *
     * @param dictField
     * @return
     */
    public List<SelectVO> getDictData(String dictField) {
        if (StringUtils.isBlank(dictField)) {
            return null;
        }
        List<SelectVO> result = dictIntegration.getDictByDictField(dictField);
        return result;
    }

    /**
     * 根据一组字典类型获取字典值列表
     *
     * @param dictTypeList
     * @return
     */
    private Map<String, List<SelectVO>> getDictDataList(List<DictType> dictTypeList) {
        if (CollectionUtils.isEmpty(dictTypeList)) {
            return new HashMap<>();
        }
        Map<String, List<SelectVO>> map = new HashMap<>();
        for (DictType dictType : dictTypeList) {
            List<SelectVO> result =
                    dictIntegration.getDictByDictField(dictType.getDictField().toUpperCase());
            if (!CollectionUtils.isEmpty(result)) {
                map.put(dictType.getPropertyName(), result);
            }
        }
        return map;
    }

    private Map<String, Map<String, String>> getDictMapList(List<DictType> dictTypeList) {
        if (CollectionUtils.isEmpty(dictTypeList)) {
            return new HashMap<>();
        }
        Map<String, Map<String, String>> map = new HashMap<>();
        for (DictType dictType : dictTypeList) {
            List<SelectVO> result =
                    dictIntegration.getDictByDictField(dictType.getDictField().toUpperCase());
            if (!CollectionUtils.isEmpty(result)) {
                Map<String, String> selectMap =
                        result.stream()
                                .collect(
                                        Collectors.toMap(
                                                SelectVO::getDictKey,
                                                SelectVO::getDictValue,
                                                (k1, k2) -> k1));
                map.put(dictType.getPropertyName(), selectMap);
            }
        }
        return map;
    }
    /**
     * 获取某个属性的字典值
     *
     * @param data
     * @param property
     * @param <T>
     * @return
     */
    private <T> String getDictValue(T data, String property) {
        BeanWrapper beanWrapper = new BeanWrapperImpl(data);
        // 字典属性和字典名称属性必须有效
        if (!beanWrapper.isReadableProperty(property)) {
            return null;
        }
        Object obj = beanWrapper.getPropertyValue(property);
        if (obj == null) {
            return null;
        }
        try {
            return obj.toString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 找到具体的字典对象
     *
     * @param dictDataVOList
     * @param dictKey
     * @return
     */
    private SelectVO filter(List<SelectVO> dictDataVOList, String dictKey) {
        return CollectionUtils.isEmpty(dictDataVOList)
                ? null
                : dictDataVOList.stream()
                        .filter(dictDataVO -> dictDataVO.getDictKey().equals(dictKey))
                        .findFirst()
                        .orElse(null);
    }
}
